﻿using System;
using Expect.Core.Errors;
using Expect.Core.Interfaces;
    
namespace Expect.Core.BaseClasses
{
    /// <summary>
    /// Base class for runnable list that could have an implementation
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TImpl"></typeparam>
    public abstract class RunnableActiveList<T, TImpl> : RunnableList<T> where T : RunnableElement where TImpl : class
    {
        private string _className;

        /// <summary>
        /// The name of the implementation's class
        /// </summary>
        public string ClassName
        {
            get
            {
                if (ClassType != null)
                    return ClassType.Name;

                return _className;
            }
            set
            {
                _className = value;
            }
        }

        /// <summary>
        /// The type of the implementation's class
        /// </summary>
        public Type ClassType { get; set; }

        /// <summary>
        /// Indicate if the element as an implementation defined
        /// </summary>
        public bool HasClass
        {
            get
            {
                return (!string.IsNullOrEmpty(ClassName)) || (ClassType != null);
            }
        }

        /// <summary>
        /// Indicate that fixture has an implementation
        /// </summary>
        public bool HasImplementation
        {
            get
            {
                return Implementation != null;
            }
        }

        /// <summary>
        /// The element implementation
        /// </summary>
        public TImpl Implementation { get; protected set; }

        /// <summary>
        /// Get an instance of the fixture's implementation
        /// </summary>
        /// <returns>an instance of the fixture's implementation</returns>
        public virtual TImpl GetImplementation(IExpectCatalog catalog)
        {
            var res = (TImpl)catalog.GetInstance(ClassType, null);
            
            if (res == null)
            {
                Status.AddError(ElementNotFoundError.Constructor(ClassType.FullName, 0));
            }
            
            return res;
        }

        /// <summary>
        /// Get an instance of the fixture's implementation
        /// </summary>
        /// <returns>an instance of the fixture's implementation</returns>
        public virtual void InitializeImplementation(IExecutionContext ctx)
        {
            Implementation = this.GetImplementation(ctx.Catalog);
        }
    }
}
